#include "PreCompile.hpp"
#include "TmpAllocatorTests.hpp"
#include "../TmpAllocator.hpp"

namespace BuildNG
{
  //////////
  // TmpPoolTests
  void TmpPoolTests::test()
  {
    TmpPool<200> pool;

    struct Block
    {
      char *ptr;
      int size;
    };
    std::vector<Block> blocks;

    Block block;
    
    for(int i = 0;i < 4;i++)
    {
      block.ptr = (char*)pool.alloc(64);
      block.size = 64;

      memset(block.ptr,i,block.size);

      blocks.push_back(block);
    }

    block.ptr = (char*)pool.alloc(1000);
    block.size = 1000;
    memset(block.ptr,4,block.size);
    blocks.push_back(block);

    block.ptr = (char*)pool.alloc(1);
    block.size = 1;
    memset(block.ptr,5,block.size);
    blocks.push_back(block);

    block.ptr = (char*)pool.alloc(2000);
    block.size = 2000;
    memset(block.ptr,6,block.size);
    blocks.push_back(block);

    for(int i = 0;i < (int)blocks.size();i++)
    {
      for(int j = 0;j < blocks[i].size;j++)
      {
        assert(blocks[i].ptr[j] == i);
      }
    }
  }

  /////////
  // TmpArrayTests
  void TmpArrayTests::test_grow()
  {
    {
      TmpArray<int,16> arr;
      for(int i = 0;i < 256;i++)
      {
        arr.append(i);
        assert(arr.get_size() == i + 1);
        for(int j = 0;j < i + 1;j++)
        {
          assert(arr[j] == j);
        }
      }
    }

    {
      TmpArray<int,16> arr;
      for(int i = 0;i < 256;i++)
      {
        arr.append(i);
        assert(arr.get_size() == i + 1);
        for(int j = 0;j < i + 1;j++)
        {
          assert(arr[j] == j);
        }
      }
    }
  }

  void TmpArrayTests::test_array_copy_ctor()
  {
    TmpArray<int,16> arr;

    for(int i = 0;i < 5;i++)
      arr.append(i);
    assert(arr.get_size() == 5);

    {
      TmpArray<int,8> b = arr;
      assert(b.get_size() == 5);
      for(int i = 0;i < b.get_size();i++)
        assert(b[i] == i);

      TmpArray<int,18> c = arr;
      assert(c.get_size() == 5);
      for(int i = 0;i < c.get_size();i++)
        assert(c[i] == i);
    }

    for(int i = 5;i < 16;i++)
      arr.append(i);

    {
      TmpArray<int,8> b = arr;
      assert(b.get_size() == 16);
      for(int i = 0;i < b.get_size();i++)
        assert(b[i] == i);

      TmpArray<int,18> c = arr;
      assert(c.get_size() == 16);
      for(int i = 0;i < c.get_size();i++)
        assert(c[i] == i);
    }

    for(int i = 16;i < 21;i++)
      arr.append(i);

    {
      TmpArray<int,8> b = arr;
      assert(b.get_size() == 21);
      for(int i = 0;i < b.get_size();i++)
        assert(b[i] == i);

      TmpArray<int,18> c = arr;
      assert(c.get_size() == 21);
      for(int i = 0;i < c.get_size();i++)
        assert(c[i] == i);
    }

    {
      TmpArray<int,8> empty;

      TmpArray<int,8> b = empty;
      assert(b.get_size() == 0);

      TmpArray<int,18> c = empty;
      assert(c.get_size() == 0);

      TmpArray<int,8> d = empty;
      assert(c.get_size() == 0);

      TmpArray<int,18> e = empty;
      assert(c.get_size() == 0);

      for(int i = 0;i < 10;i++)
      {
        d.append(i);
        e.append(i);
      }

      for(int i = 0;i < 10;i++)
      {
        assert(d[i] == i);
        assert(e[i] == i);
      }
    }
  }

  void TmpArrayTests::test_assignment_operator()
  {
    TmpArray<int,16> arr;
    for(int i = 0;i < 5;i++)
      arr.append(i);
    assert(arr.get_size() == 5);

    TmpArray<int,8> b;
    TmpArray<int,18> c;

    {
      b = arr;
      assert(b.get_size() == 5);
      for(int i = 0;i < b.get_size();i++)
        assert(b[i] == i);

      c = arr;
      assert(c.get_size() == 5);
      for(int i = 0;i < c.get_size();i++)
        assert(c[i] == i);
    }

    for(int i = 5;i < 16;i++)
      arr.append(i);

    {
      b = arr;
      assert(b.get_size() == 16);
      for(int i = 0;i < b.get_size();i++)
        assert(b[i] == i);

      c = arr;
      assert(c.get_size() == 16);
      for(int i = 0;i < c.get_size();i++)
        assert(c[i] == i);
    }

    for(int i = 16;i < 21;i++)
      arr.append(i);

    {
      b = arr;
      assert(b.get_size() == 21);
      for(int i = 0;i < b.get_size();i++)
        assert(b[i] == i);

      c = arr;
      assert(c.get_size() == 21);
      for(int i = 0;i < c.get_size();i++)
        assert(c[i] == i);
    }

    {
      TmpArray<int,8> empty;

      TmpArray<int,8> b;
      b = empty;
      assert(b.get_size() == 0);

      TmpArray<int,18> c;
      c = empty;
      assert(c.get_size() == 0);

      TmpArray<int,8> d;
      d = empty;
      assert(c.get_size() == 0);

      TmpArray<int,18> e;
      e = empty;
      assert(c.get_size() == 0);

      for(int i = 0;i < 10;i++)
      {
        d.append(i);
        e.append(i);
      }

      for(int i = 0;i < 10;i++)
      {
        assert(d[i] == i);
        assert(e[i] == i);
      }
    }
  }

  static int tc_num_instances = 0;

  class TrackableClass
  {
  public:
    TrackableClass()
    {
      cached_this_ptr = this;
      tc_num_instances++;
    }

    TrackableClass(int index)
    {
      cached_this_ptr = this;
      tc_num_instances++;
      this->index = index;
    }

    TrackableClass(const TrackableClass &src)
    {
      cached_this_ptr = this;
      tc_num_instances++;
      index = src.index;
    }

    ~TrackableClass()
    {
      assert(cached_this_ptr);
      cached_this_ptr = 0;
      tc_num_instances--;
    }

    TrackableClass *cached_this_ptr;
    int index;
  };

  void TmpArrayTests::test_elements_ctor_dtor()
  {
    {
      TmpArray<TrackableClass,8> arr;
      for(int i = 0;i < 4;i++)
      {
        arr.append(TrackableClass());
      }

      for(int i = 0;i < 4;i++)
      {
        assert(&arr[i] == arr[i].cached_this_ptr);
      }
    }
    assert(tc_num_instances == 0);

    {
      TmpArray<TrackableClass,8> arr;
      for(int i = 0;i < 16;i++)
      {
        arr.append(TrackableClass());
      }

      for(int i = 0;i < 16;i++)
      {
        assert(&arr[i] == arr[i].cached_this_ptr);
      }
    }
    assert(tc_num_instances == 0);

    {
      TmpArray<TrackableClass,8> arr;
      for(int i = 0;i < 16;i++)
      {
        arr.append(TrackableClass());
      }

      TmpArray<TrackableClass,8> arr2 = arr;
      TmpArray<TrackableClass,8> arr3;
      arr3 = arr;

      for(int i = 0;i < 16;i++)
      {
        assert(&arr[i] == arr[i].cached_this_ptr);
        assert(&arr2[i] == arr2[i].cached_this_ptr);
        assert(&arr3[i] == arr3[i].cached_this_ptr);
      }
    }
    assert(tc_num_instances == 0);
  }

  void TmpArrayTests::test_remove()
  {
    for(int j = 0;j < 4;j++)
    {
      int num_elems = 4 << j;

      {
        TmpArray<int,8> arr;
        for(int i = 0;i < num_elems;i++)
          arr.append(i);

        for(int i = 0;i < num_elems;i++)
        {
          arr.remove(arr.get_size() - 1);
          for(int k = 0;k < arr.get_size();k++)
          {
            assert(arr[k] == k);
          }
        }

        assert(arr.get_size() == 0);
      }

      {
        TmpArray<int,8> arr;
        for(int i = 0;i < num_elems;i++)
          arr.append(i);

        for(int i = 0;i < num_elems;i++)
        {
          arr.remove(0);

          for(int k = 0;k < arr.get_size();k++)
          {
            assert(arr[k] == k + i + 1);
          }
        }

        assert(arr.get_size() == 0);
      }
    }

    {
      TmpArray<int,8> arr;
      arr.append(0);
      arr.append(1);
      arr.append(2);
      arr.append(3);
      arr.append(4);
      arr.remove(2);

      assert(arr[0] == 0);
      assert(arr[1] == 1);
      assert(arr[2] == 3);
      assert(arr[3] == 4);
    }
  }

  void TmpArrayTests::test_replace()
  {
    {
      TmpArray<TrackableClass,8> arr;
      for(int i = 0;i < 8;i++)
      {
        arr.append(TrackableClass(i));
      }
      
      arr.replace(1,7,TrackableClass(-1));

      assert(arr.get_size() == 3);
      assert(arr[0].index == 0);
      assert(arr[1].index == -1);
      assert(arr[2].index == 7);

      for(int i = 0;i < 3;i++)
        assert(arr[i].cached_this_ptr = &arr[i]);
    }

    assert(tc_num_instances == 0);
  }
}
